$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
$KCODE = 'utf-8'

require 'UPnP/device'
require 'UPnP/service/content_directory'
require 'builder'
require 'test/unit'
require 'rexml/document'
include REXML

TEST_DIR1 = '../test-data/A'
TEST_DIR2 = '../test-data/Z'


class TestContentDirectory < Test::Unit::TestCase
  class FakeWEBrickSocket
  
      #Method that emulates Socket addr return
      def addr
        #_, port, host, addr = 
    
        return nil, 80, 'localhost', '127.0.0.1'
      end
  end
  
  class DeviceMockup
    #Emulating Device#parent method
     def parent
       nil
     end
     
     def type
       'MediaServer'
     end    
  end

  @@cd = UPnP::Service::ContentDirectory.new DeviceMockup.new, 'ContentDirectory' do |cd|
    #trick to emulate WEBrick Socket presence, its .addr method is called later
    Thread.current[:WEBrickSocket] = FakeWEBrickSocket.new
 
    cd.add_directory TEST_DIR1
    cd.add_directory TEST_DIR2
  end

  def setup
  
#    @device = UPnP::Device.create('MediaServer', 'AVTEST')
#    
#    @cd = @device.add_service 'ContentDirectory' do |cd|
    #self - is a placehodler instead of the Device pointer

  end 
 
  def test_didl_xml
    _, result, number_returned, total_matches, update_id = @@cd.Browse(0, 'BrowseDirectChildren', '*', 0, 0, nil)
    
    assert_equal(nil, _, 'First returned parameter must be nil')
    assert_equal(2, number_returned, 'Returned objects under root')
    assert_equal(2, total_matches, 'Total objects under root')
    
    xml = Document.new(result)
    c = xml.elements["//container[dc:title='A']"] 
    a_id = c.attributes['id']
    a_childCount = c.attributes['childCount']
    a_parentId = c.attributes['parentId']
    a_class = c.elements['upnp:class'].text
    a_writeStatus = c.elements['upnp:writeStatus'].text
    a_storageUsed = c.elements['upnp:storageUsed'].text
    
    assert_equal(a_id, '1', 'A id')
    assert_equal(a_childCount, '3')
    assert_equal(a_parentId, '0')
    assert_equal(a_class, 'object.container.storageFolder')
    assert_equal(a_writeStatus, 'NOT_WRITABLE')
    assert(a_storageUsed.to_i > 0, 'Overal storage used must be positive')

    #Browser for object Metadata
    _, result, number_returned, total_matches, update_id = @@cd.Browse(a_id, 'BrowseDirectChildren', '*', 0, 0, nil)
    e_id = (xml = Document.new(result).elements["//item[dc:title='e']"]).attributes['id']
    _, result, number_returned, total_matches, update_id = @@cd.Browse(e_id, 'BrowseMetadata', '*', 0, 0, nil)
    
    assert_equal(nil, _, 'First returned parameter must be nil')
    assert_equal(1, number_returned, 'Returned objects for metadata search')
    assert_equal(1, total_matches, 'Total objects for metadata search')
    
    i = Document.new(result).elements["//item[dc:title='e']"] 

    assert_nil(i.attributes['childCount'])
    assert_equal(a_id, i.attributes['parentId'], 'A is a parent of this item')
    assert_equal('object.item.textItem', i.elements['upnp:class'].text)
    assert_match(%r[^http-get:\*:text/plain:.*], i.elements['res'].attributes['protocolInfo'])
    assert_match(%r[^http://\d[\d:\.]+/MediaServer/ContentDirectory/#{a_id}/.*], i.elements['res'].text)
    assert(i.elements['res'].attributes['size'].to_i > 0, 'Size must be >0')
  end
  
  #check one of the children of Z for its video properties
  def test_videoItem_data
    #TODO: must be replaced with search
    _, result, number_returned, total_matches, update_id = @@cd.Browse(0, 'BrowseDirectChildren', '*', 0, 0, nil)
    
    z_id = Document.new(result).elements["//container[dc:title='Z']"].attributes['id']
    _, result, number_returned, total_matches, update_id = @@cd.Browse(z_id, 'BrowseDirectChildren', '*', 0, 0, nil)

    xml = Document.new(result)
    i = xml.elements["//item[dc:title='AVI movie']"] 
    assert_nil(i.attributes['childCount'])
    assert_equal(z_id, i.attributes['parentId'], 'Z is a parent of this item')
    assert_equal('object.item.videoItem', i.elements['upnp:class'].text)
    assert_match(%r[^http-get:\*:video/.+:.*], i.elements['res'].attributes['protocolInfo'])
    assert_match(%r[^http://\d[\d:\.]+/MediaServer/ContentDirectory/#{z_id}/.*], i.elements['res'].text)
    assert(i.elements['res'].attributes['size'].to_i > 0, 'Size must be >0')

    i = xml.elements["//item[dc:title='picture']"] 
    assert_nil(i.attributes['childCount'])
    assert_equal(z_id, i.attributes['parentId'], 'Z is a parent of this item')
    assert_equal('object.item.imageItem.photo', i.elements['upnp:class'].text)
    assert_match(%r[^http-get:\*:image/jpeg:.*], i.elements['res'].attributes['protocolInfo'])
    assert_match(%r[^http://\d[\d:\.]+/MediaServer/ContentDirectory/#{z_id}/.*], i.elements['res'].text)
    assert(i.elements['res'].attributes['size'].to_i > 0, 'Size must be >0')
  end
  
  def test_browse_structure
    # A
    #  e
    #  C
    #   d
    #  B
    #   b
    #   c
    #   a
    #   D
    #children of A -> BCe
    _, result, number_returned, total_matches, update_id = @@cd.Browse(1, 'BrowseDirectChildren', '*', 0, 3, nil)

    dir = ''
    xml = Document.new(result)
    xml.each_element('//dc:title') {|e| dir << e.text}
      
    assert_equal('BCe', dir, 'Files/dirs under A')
    assert_equal(nil, _, 'First returned parameter must be nil')
    assert_equal(3, number_returned, 'Returned objects under A')
    assert_equal(3, total_matches, 'Total objects under A')
        
    #for the following testing
    b_id = xml.elements["//container[dc:title='B']"].attributes['id']
    e_id = xml.elements["//item[dc:title='e']"].attributes['id']

    
    #children of B -> Dabc
    #1 - all children
    _, result, number_returned, total_matches, update_id = @@cd.Browse(b_id, 'BrowseDirectChildren', '*', 0, 0, nil)
    
    xml = Document.new(result)

    #for the following testing
    d_id = xml.elements["//container[dc:title='D']"].attributes['id']

    dir = ''
    xml.each_element('//dc:title') {|e| dir << e.text}
      
    assert_equal('Dabc', dir, 'Files/dirs under B')
    assert_equal(nil, _, 'First returned parameter must be nil')
    assert_equal(4, number_returned, 'Returned objects under B')
    assert_equal(4, total_matches, 'Total objects under B')

    #2 - range 2..4
    _, result, number_returned, total_matches, update_id = @@cd.Browse(b_id, 'BrowseDirectChildren', '*', 1, 2, nil)
    
    dir = ''
    xml = Document.new(result)
    xml.each_element('//dc:title') {|e| dir << e.text}
      
    assert_equal('ab', dir, 'Files/dirs under B')
    assert_equal(nil, _, 'First returned parameter must be nil')
    assert_equal(2, number_returned, 'Returned objects under B')
    assert_equal(4, total_matches, 'Total objects under B')

    #D - empty
    _, result, number_returned, total_matches, update_id = @@cd.Browse(d_id, 'BrowseDirectChildren', '*',  0, 2, nil)
    
    xml = Document.new(result)
    
    assert_nil(xml.elements['//dc:title'])
    assert_equal(0, number_returned, 'Returned objects under D')
    assert_equal(0, total_matches, 'Total objects under D')

    #e - not a container
    #TODO: catch WebBrick exception
    assert_raise(UPnP::Service::Error) {@@cd.Browse(e_id, 'BrowseDirectChildren', '*',  0, 0, nil)}
  end
end